<?php

namespace Hilaoyu\ComputeCloudClient\Api;


use Hilaoyu\ComputeCloudClient\AssetModel;
use Hilaoyu\ComputeCloudClient\AssetModels;
use Hilaoyu\ComputeCloudClient\ctyun\CtyunClientEcs;
use Hilaoyu\ComputeCloudClient\huawei\DetachServerInterfaceResponse;
use Hilaoyu\ComputeCloudClient\huawei\ShowServerInterfaceResponse;
use Hilaoyu\ComputeCloudClient\Interfaces\ApiEcsInterface;
use Hilaoyu\Utils\UtilArr;
use Hilaoyu\Utils\UtilFile;
use Hilaoyu\Utils\UtilHttp;
use Hilaoyu\Utils\UtilStr;
use Hilaoyu\Utils\UtilSupport;


/**
 * Class HuaWeiEcs
 * @package Hilaoyu\ComputeCloudClient\Api
 * @property  CtyunClientEcs $client
 */
class CtyunEcs extends CtyunApiBase implements ApiEcsInterface
{
    public function regionsDescribe(): array
    {
        $models = [];
        try {
            $data = $this->client->describeRegions();
            if (is_null($data)) {
                throw new \Exception('返回数据错误:' . $this->client->getError(false));
            }
            foreach ($data as $datum) {
                $id = UtilArr::get($datum, 'regionID');
                if (!$id) {
                    continue;
                }
                $models[] = ["id" => $id, "name" => UtilArr::get($datum, 'regionName')];
            }

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;
    }

    public function zonesDescribe($regionId = ''): array
    {
        $regionId = $this->getRegionId($regionId);
        if (!$regionId) {
            return [];
        }

        $models = [];
        try {
            $data = $this->client->describeZones($regionId);
            if (is_null($data)) {
                throw new \Exception('返回数据错误:' . $this->client->getError(false));
            }
            foreach ($data as $datum) {
                $id = UtilArr::get($datum, 'name');
                if (!$id) {
                    continue;
                }
                $models[] = ["id" => $id, "name" => UtilArr::get($datum, 'azDisplayName')];
            }
            if (empty($models)) {
                $models[] = ["id" => "default", "name" => "默认"];
            }

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;
    }


    //安全组
    public function securityGroupCreate(string $securityGroupName = null, string $vpcId = null, string $securityGroupType = 'normal', $regionId = '', $resourceGroupId = null): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);
        if (!$securityGroupName) {
            $securityGroupName = UtilStr::randString(12);
        }
        try {
            $client = $this->clientVpc();
            $id = $client->createSecurityGroup($securityGroupName, (string)$vpcId, $regionId);

            if (!$id) {
                throw new \Exception('返回数据错误:' . $client->getError(false));
            }

            $this->securityGroupEgressAuthorize($id,"","accept","0.0.0.0/0","all",null,null,100,$regionId);

            return $this->securityGroupDescribe($id, $regionId);

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }

    public function securityGroupDelete(string $securityGroupId, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $securityGroupId = trim($securityGroupId);
        if (!$securityGroupId) {
            return false;
        }
        if (!$this->securityGroupDescribe($securityGroupId)) {
            return true;
        }
        try {
            $client = $this->clientVpc();
            $result = $client->deleteSecurityGroup($securityGroupId, $regionId);
            if (!$result) {
                throw new \Exception('返回数据错误:' . $client->getError(false));
            }
            return (bool)$result;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return false;
    }

    public function securityGroupsDescribe(array $securityGroupIds = [], string $securityGroupName = null, string $vpcId = null, int $pageSize = 100, int $pageNumber = 1, $regionId = '', $resourceGroupId = null): AssetModels
    {
        $regionId = $this->getRegionId($regionId);
        $models = new AssetModels();
        try {
            $client = $this->clientVpc();
            $data = $client->listSecurityGroups($securityGroupIds, (string)$securityGroupName, (string)$vpcId, $pageSize, $pageNumber, $regionId);

            if (is_null($data)) {
                throw new \Exception('返回数据错误:' . $client->getError(false));
            }
            foreach ($data as $datum) {
                $id = UtilArr::get($datum, "id");
                if (!$id) {
                    continue;
                }

                $model = new AssetModel();
                $model->type = 'sg';
                $model->asset_id = $id;
                $model->name = UtilArr::get($datum, "securityGroupName");
                $model->os_type = 'normal';
                $model->bind_asset_id = UtilArr::get($datum, "vpcID");
                $model->region_id = (string)$regionId;

                $models->push($model);
            }

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;
    }

    public function securityGroupDescribe(string $securityGroupId, $regionId = ''): ?AssetModel
    {
        $models = $this->securityGroupsDescribe([$securityGroupId], null, null, 10, 1, $regionId);
        if (!$models) {
            return null;
        }


        return $models->first(function ($item) use ($securityGroupId) {
            return $item->asset_id == $securityGroupId;
        });
        return null;
    }


    /**
     * 添加入方向规则
     * @param $securityGroupId
     * @param string $ipProtocol tcp|udp|icmp|gre|all
     * @param string $portRange 目的端安全组开放的传输层协议相关的端口范围。取值范围: TCP/UDP协议：取值范围为1~65535。使用斜线（/）隔开起始端口和终止端口。例如：1/200;ICMP协议：-1/-1;GRE协议：-1/-1;IpProtocol取值为all：-1/-1
     * @param string $policy accept|drop
     * @param string $sourceCidrIp 源端IPv4 CIDR地址段。支持CIDR格式和IPv4格式的IP地址范围
     * @param string $sourcePortRange 源端安全组开放的传输层协议相关的端口范围。取值范围: TCP/UDP协议：取值范围为1~65535。使用斜线（/）隔开起始端口和终止端口。例如：1/200;ICMP协议：-1/-1;GRE协议：-1/-1;IpProtocol取值为all：-1/-1
     * @param string $destCidrIp 目的端IPv4 CIDR地址段。支持CIDR格式和IPv4格式的IP地址范围
     * @param int $priority 1~100
     * @param string $regionId
     * @return array
     */
    public function securityGroupAuthorize($securityGroupId, $portRange, $policy = 'accept', $sourceCidrIp = '0.0.0.0/0', $ipProtocol = 'tcp', $sourcePortRange = null, $destCidrIp = null, $priority = 1, $regionId = ''): bool
    {
        $this->securityGroupRevoke($securityGroupId, $portRange, $policy, $sourceCidrIp, $ipProtocol, $sourcePortRange, $destCidrIp, $regionId);

        $regionId = $this->getRegionId($regionId);
        $portRange = $this->formatSecurityGroupRulePortRange($portRange);
        $sourcePortRange = $this->formatSecurityGroupRulePortRange($sourcePortRange);
        //dump($portRange);
        if ('all' == $ipProtocol) {
            $ipProtocol = "ANY";
        }
        try {
            $client = $this->clientVpc();
            $result = $client->createSecurityGroupRuleIngress((string)$securityGroupId, (string)$portRange, (string)$policy, (int)$priority, (string)$ipProtocol, (string)$sourceCidrIp, (string)$regionId);

            if (!$result) {
                throw new \Exception('返回数据错误:' . $client->getError(false));
            }

            return (bool)$result;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return false;

    }

    public function securityGroupRevoke($securityGroupId, $portRange, $policy = 'accept', $sourceCidrIp = '0.0.0.0/0', $ipProtocol = 'tcp', $sourcePortRange = null, $destCidrIp = null, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $portRange = $this->formatSecurityGroupRulePortRange($portRange);
        $sourcePortRange = $this->formatSecurityGroupRulePortRange($sourcePortRange);
        if ('all' == $ipProtocol) {
            $ipProtocol = "ANY";
        }
        try {
            $client = $this->clientVpc();

            $data = $client->listSecurityGroupRules($securityGroupId, "ingress", $regionId);
            if (is_null($data)) {
                throw new \Exception('返回数据错误:' . $client->getError(false));
            }

            $rules = UtilArr::filter($data, function ($item) use ($portRange, $sourceCidrIp, $policy, $ipProtocol) {
                $bool = UtilArr::get($item, "range") == $portRange
                    && UtilStr::lower($policy) == UtilStr::lower(UtilArr::get($item, "action"))
                    && UtilStr::upper($ipProtocol) == UtilStr::upper(UtilArr::get($item, "protocol"))
                    && (
                        UtilArr::get($item, "destCidrIp") == $sourceCidrIp
                        || (in_array($sourceCidrIp, ['0.0.0.0/0', '::/0']) && UtilArr::get($item, "destCidrIp"))
                    );
                return $bool;
            });

            if (empty($rules)) {
                return true;
            }

            $status = true;
            foreach ($rules as $rule) {
                $ruleId = UtilArr::get($rule, "id");
                if (!$ruleId) {
                    continue;
                }
                $result = $client->deleteSecurityGroupRuleIngress($securityGroupId, $ruleId, $regionId);
                if (!$result) {
                    throw new \Exception('返回数据错误:' . $client->getError(false));
                }
                $status = $status && (bool)$result;
            }
            return $status;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return false;

    }

    public function securityGroupEgressAuthorize($securityGroupId, $portRange, $policy = 'accept', $destCidrIp = '0.0.0.0/0', $ipProtocol = 'tcp', $sourcePortRange = null, $sourceCidrIp = null, $priority = 1, $regionId = ''): bool
    {
        $this->securityGroupEgressRevoke($securityGroupId, $portRange, $policy, $destCidrIp, $ipProtocol, $sourcePortRange, $sourceCidrIp, $regionId);

        $regionId = $this->getRegionId($regionId);
        $portRange = $this->formatSecurityGroupRulePortRange($portRange);
        $sourcePortRange = $this->formatSecurityGroupRulePortRange($sourcePortRange);
        //dump($portRange);
        if ('all' == $ipProtocol) {
            $ipProtocol = "ANY";
        }
        try {
            $client = $this->clientVpc();
            $result = $client->createSecurityGroupRuleEgress((string)$securityGroupId, (string)$portRange, (string)$policy, (int)$priority, (string)$ipProtocol, (string)$destCidrIp, (string)$regionId);

            if (!$result) {
                throw new \Exception('返回数据错误:' . $client->getError(false));
            }

            return (bool)$result;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return false;
    }

    public function securityGroupEgressRevoke($securityGroupId, $portRange, $policy = 'accept', $destCidrIp = '0.0.0.0/0', $ipProtocol = 'tcp', $sourcePortRange = null, $sourceCidrIp = null, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $portRange = $this->formatSecurityGroupRulePortRange($portRange);
        $sourcePortRange = $this->formatSecurityGroupRulePortRange($sourcePortRange);
        if ('all' == $ipProtocol) {
            $ipProtocol = "ANY";
        }
        try {
            $client = $this->clientVpc();

            $data = $client->listSecurityGroupRules($securityGroupId, "egress", $regionId);
            if (is_null($data)) {
                throw new \Exception('返回数据错误:' . $client->getError(false));
            }

            $rules = UtilArr::filter($data, function ($item) use ($portRange, $destCidrIp, $policy, $ipProtocol) {
                $bool = UtilArr::get($item, "range") == $portRange
                    && UtilStr::lower($policy) == UtilStr::lower(UtilArr::get($item, "action"))
                    && UtilStr::upper($ipProtocol) == UtilStr::upper(UtilArr::get($item, "protocol"))
                    && (
                        UtilArr::get($item, "destCidrIp") == $destCidrIp
                        || (in_array($destCidrIp, ['0.0.0.0/0', '::/0']) && UtilArr::get($item, "destCidrIp"))
                    );
                return $bool;
            });

            if (empty($rules)) {
                return true;
            }

            $status = true;
            foreach ($rules as $rule) {
                $ruleId = UtilArr::get($rule, "id");
                if (!$ruleId) {
                    continue;
                }
                $result = $client->deleteSecurityGroupRuleEgress($securityGroupId, $ruleId, $regionId);
                if (!$result) {
                    throw new \Exception('返回数据错误:' . $client->getError(false));
                }
                $status = $status && (bool)$result;
            }
            return $status;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return false;
    }


    /**
     * @param null $instanceType 指定实例类型可以使用的镜像。ecs.g5.large
     * @param null $osType 镜像的操作系统类型 windows , linux
     * @param string $architecture 镜像的体系架构。取值范围： i386 x86_64
     * @param null $imageName 镜像名称  centos
     * @param int $pageNumber
     * @param int $pageSize
     * @param string $regionId
     * @return array
     */
    public function imagesDescribe(string $imageName = null, $imageId = null, $instanceType = null, $osType = null, $architecture = null, $regionId = '', $zoneId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);
        $models = new AssetModels();
        try {

            $client = $this->clientIms();
            $data_global = $client->listImages(1, (string)$instanceType, (string)$imageName, $regionId, (string)$zoneId);
            if (is_null($data_global)) {
                throw new \Exception('返回数据错误:' . $client->getError(false));
            }

            $data_private = $client->listImages(0, (string)$instanceType, (string)$imageName, $regionId, (string)$zoneId);
            if (is_null($data_private)) {
                throw new \Exception('返回数据错误:' . $client->getError(false));
            }


            //dump($data);
            $data = array_merge($data_global, $data_private);
            foreach ($data as $datum) {
                $id = UtilArr::get($datum, "imageID");
                if (!$id) {
                    continue;
                }
                $azName = UtilArr::get($datum, "azName");


                $model = new AssetModel();
                $model->type = 'image';
                $model->asset_id = $id;
                $model->region_id = $regionId;
                $model->zone_id = $azName;
                $model->name = UtilArr::get($datum, "imageName");
                $model->os_type = UtilArr::get($datum, "osType");
                $model->instance_type = $this->formatImageVisibilityToCode(UtilArr::get($datum, "imageVisibility"));
                $model->os = (string)UtilArr::get($datum, "osDistro") . "-" . (string)UtilArr::get($datum, "architecture") . "-" . (string)UtilArr::get($datum, "osVersion");

                $models->push($model);
            }

            if ($imageId || $osType || $architecture) {
                $models = $models->filter(function ($item) use ($imageId, $osType, $architecture) {
                    $bool = true;
                    if ($bool && $imageId) {
                        $bool = $bool && $imageId == $item->asset_id;
                    }
                    if ($bool && $osType) {
                        $bool = $bool && $osType == $item->os_type;
                    }
                    if ($bool && $architecture) {
                        $bool = $bool && UtilStr::contains($model->os, $architecture);
                    }

                    return $bool;
                });
            }

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;
    }


    public function imageDescribe(string $imageId, $regionId = '', $zoneId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);
        try {
            $client = $this->clientIms();
            $datum = $client->describeImage($imageId, $regionId);
            if (is_null($datum)) {
                throw new \Exception('返回数据错误:' . $client->getError(false));
            }
            $id = UtilArr::get($datum, "imageID");
            if (!$id) {
                throw new \Exception('返回数据错误:镜像ID为空');
            }
            $azName = UtilArr::get($datum, "azName");
            if ($zoneId && $azName && $zoneId != $azName) {
                return null;
            }

            $model = new AssetModel();
            $model->type = 'image';
            $model->asset_id = $id;
            $model->region_id = $regionId;
            $model->zone_id = $azName;
            $model->name = UtilArr::get($datum, "imageName");
            $model->os_type = UtilArr::get($datum, "osType");
            $model->instance_type = $this->formatImageVisibilityToCode(UtilArr::get($datum, "imageVisibility"));
            $model->os = (string)UtilArr::get($datum, "osDistro") . "-" . (string)UtilArr::get($datum, "architecture") . "-" . (string)UtilArr::get($datum, "osVersion");

            return $model;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }

    public function instanceTypesDescribe(array $instanceTypes = [], string $zoneId = '', string $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);
        $models = new AssetModels();
        try {
            $data = $this->client->listFlavors("", UtilArr::first($instanceTypes), $zoneId, $this->getRegionId($regionId));
            if (is_null($data)) {
                throw new \Exception('返回数据错误:' . $this->client->getError(false));
            }
            foreach ($data as $datum) {
                $model = $this->formatInstanceTypeToModel($datum, $zoneId, $regionId);
                if (!$model) {
                    continue;
                }
                if (!empty($instanceTypes)) {
                    if (!in_array($model->asset_id, $instanceTypes)) {
                        continue;
                    }
                }
                $models->push($model);

            }

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;
    }

    public function instanceTypeDescribe(string $instanceType, string $zoneId = '', string $regionId = ''): ?AssetModel
    {
        $models = $this->instanceTypesDescribe([$instanceType]);
        if (!$models) {
            return null;
        }

        return $models->first(function ($item) use ($instanceType) {
            return $item->asset_id == $instanceType;
        });
        return null;
    }



    //实例

    /**
     * 创建实例
     * https://next.api.aliyun.com/api/Ecs/2014-05-26/CreateInstance?params={}
     * @param string $instanceType 实例规格
     * @param string $imageId 镜像文件ID
     * @param string $password 密码
     * @param string $instanceName 实例名 允许大小写英文字母、数字和短横线（-）
     * @param string $vSwitchId 虚拟交换机ID
     * @param int $internetMaxBandwidth 公网带宽峰值 0为不需要公网IP
     * @param null $securityGroupId 安全组ID
     * @param int $period 时长
     * @param string $periodUnit 时长单位 取值范围：Week和Month（默认
     * @param string $instanceChargeType 实例的付费方式。取值范围： PrePaid：包年包月,PostPaid 按量付费;选择该类付费方式时，您必须确认自己的账号支持余额支付/信用支付，否则将返回 InvalidPayMethod的错误提示。 PostPaid（默认）：按量付费。
     * @param string $internetChargeType 网络计费类型。取值范围：PayByBandwidth：按固定带宽计费。 PayByTraffic（默认）：按使用流量计费
     * @param array $request_data 其它数据
     * @param string $regionId
     * @param null $resourceGroupId 资源组ID
     * @return array
     */
    public function instanceCreate(string $instanceType, string $imageId, string $password, string $instanceName = null, string $vSwitchId = null, $internetMaxBandwidth = 0, $securityGroupId = null, $period = 1, $periodUnit = 'Month', $instanceChargeType = 'PostPaid', $internetChargeType = 'PayByTraffic', int $systemDiskSize = null, $zoneId = null, $regionId = '', $resourceGroupId = null): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);

        $internetMaxBandwidth = intval($internetMaxBandwidth);
        try {

            $image = $this->imageDescribe($imageId);
            if (!$image) {
                throw new \Exception('镜像不存在');
            }

            $instanceTypeModel = $this->instanceTypeDescribe($instanceType);
            if (!$instanceTypeModel) {
                throw new \Exception('实例规格不存在不存在');
            }

            if (!$instanceName) {
                $instanceName = UtilStr::randString(12);
            }
            if (!$password) {
                $password = UtilStr::randPassword(16);
            }
            $systemDiskSize = intval($systemDiskSize);

            if (!$vSwitchId) {
                throw new \Exception('子网ID不能为空');

            }
            if (!$vSwitch = $this->api->vpc($regionId)->vSwitchDescribe($vSwitchId)) {
                throw new \Exception("子网不存在:" . $vSwitchId);

            }

            $onDemand = true;
            if ('PrePaid' == $instanceChargeType) {
                $onDemand = false;
            }

            $ids = $this->client->createServers($image->asset_id, $image->instance_type, $instanceTypeModel->asset_id, $vSwitch->bind_asset_id, $vSwitch->asset_id, $instanceName, $password, $systemDiskSize, [(string)$securityGroupId], $internetMaxBandwidth, $onDemand, UtilStr::upper($periodUnit), $period, (string)$zoneId, $regionId);
            if (is_null($ids)) {
                throw new \Exception("接口返回错误:" . $this->client->getError(false));
            }
            $id = UtilArr::first($ids);
            if (!$id) {
                throw new \Exception('返回Id为空');
            }


            $model = new AssetModel();
            $model->type = 'ecs';
            $model->asset_id = $id;
            $model->name = (string)$instanceName;
            $model->instance_type = (string)$instanceType;
            $model->region_id = (string)$regionId;
            $model->os_password = (string)$password;

            $model->os_type = $image->os_type;
            $model->os = $image->name;
            $model->os_image = $image->asset_id;
            $model->cpu = $instanceTypeModel->cpu;
            $model->memory = $instanceTypeModel->memory;
            $model->bandwidth = (int)$internetMaxBandwidth;

            $model->os_account = UtilStr::contains($model->os_type, 'Windows', false) ? 'administrator' : 'root';

            $model->status = 'Pending';
            $model->pay_change_type = $instanceChargeType;
            if ($internetMaxBandwidth > 0) {
                $model->public_ip = $this->publicIpAddressAllocate($model->asset_id, $internetMaxBandwidth, $regionId);
            }

            return $model;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }

    public function publicIpAddressAllocate(string $instanceId, int $bandwidth = 100, $regionId = ''): string
    {
        $regionId = $this->getRegionId($regionId);
        $ipAddress = '';
        try {
            $model = $this->instanceDescribe($instanceId);
            if (!$model) {
                throw new \Exception('ecs不存在');
            }
            if ($model->public_ip) {
                $ipAddress = $model->public_ip;
                return $ipAddress;
            }
            $vpcApi = $this->api->vpc($regionId);
            if ($bandwidth <= 0) {
                $bandwidth = 10;
            }
            $ipModel = $vpcApi->eipAddressAllocate($bandwidth, "PostPaid", "PayByTraffic", "BGP", "Mouth", 1, "eip-" . $model->name, $regionId);

            if (!$ipModel) {
                throw new \Exception('申请EIP出错:' . $vpcApi->getError(false));
            }

            if (!$vpcApi->eipAddressAssociate($ipModel->asset_id, $model->asset_id, $model->type, $regionId)) {
                throw new \Exception('绑定EIP出错:' . $vpcApi->getError(false));
            }
            $ipAddress = $ipModel->primary_ip;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $ipAddress;
    }


    public function instancesDescribe(array $instanceIds = [], $vSwitchId = null, $zoneId = "", $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);
        $models = new AssetModels();
        try {
            $vpcId = "";
            if ($vSwitchId) {
                $vpcApi = $this->api->vpc($regionId);
                $vSwitch = $vpcApi->vSwitchDescribe($vSwitchId, $regionId);
                if (!$vSwitch) {
                    throw new \Exception("查询子网出错:" . $vpcApi->getError(false));
                }
                $vpcId = $vSwitch->bind_asset_id;
            }

            $data = $this->client->ListServers($instanceIds, (string)$vpcId, "", (string)$zoneId, $regionId);


            if (is_null($data)) {
                throw new \Exception("接口返回错误:" . $this->client->getError(false));
            }
            foreach ($data as $datum) {
                if ($model = $this->formatServerDetailToModel($datum)) {
                    if ('Deleted' != $model->status) {
                        $models->push($model);
                    }

                }
            }

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;
    }

    public function instanceDescribe(string $instanceId, $zoneId = "", $regionId = ''): ?AssetModel
    {
        $models = $this->instancesDescribe([$instanceId], "", $zoneId, $regionId);
        if (!$models) {
            return null;
        }

        return $models->first(function ($item) use ($instanceId) {
            return $item->asset_id == $instanceId;
        });
        return null;
    }


    public function instancesStart(array $instanceId, $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);
        $models = new AssetModels();
        try {
            $this->client->batchStartServers($instanceId, $regionId);

            return $this->instancesDescribe($instanceId, null, "", $regionId);

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;
    }

    public function instancesStatusDescribe(array $instanceId, $regionId = ''): AssetModels
    {
        return $this->instancesDescribe($instanceId, null, $regionId);
    }

    public function instanceStatusDescribe(string $instanceId, $regionId = ''): ?AssetModel
    {
        $models = $this->instancesStatusDescribe([$instanceId], $regionId);
        if (!$models) {
            return null;
        }

        return $models->first(function ($item) use ($instanceId) {
            return $item->asset_id == $instanceId;
        });
    }

    public function instancesStop(array $instanceId, $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);
        $models = new AssetModels();
        try {
            $this->client->batchStopServers($instanceId, $regionId);

            return $this->instancesDescribe($instanceId, null, "", $regionId);

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;
    }

    public function instancesReboot(array $instanceId, $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);

        $models = new AssetModels();
        try {
            $this->client->batchRebootServers($instanceId, $regionId);
            $this->client->batchStartServers($instanceId, $regionId);

            return $this->instancesDescribe($instanceId, null, "", $regionId);

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;
    }

    public function instancesDelete(array $instanceId, $force = false, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        if (empty($instanceId)) {
            return true;
        }

        $models = $this->instancesDescribe($instanceId, "","", $regionId);

        try {


            $result = $this->client->deleteServers($instanceId, $regionId);

            $vpcClient = $this->clientVpc();
            UtilSupport::reTry(function () use ($models,$vpcClient,$regionId){
                $delIpResult = true;
                foreach ($models->toArray() as $model) {
                    if ($model->public_ip) {
                        $delIpResult = $delIpResult && $vpcClient->deletePublicipByIp($model->public_ip,$regionId);
                    }
                }
                if($delIpResult){
                    return true;
                }
            },5,12);

            return (bool)$result;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return false;
    }

    public function instanceAttributeModify(string $instanceId, string $password = '', string $name = '', string $hostName = '', $userData = null, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $name = trim($name);
        try {

            $model = $this->instanceDescribe($instanceId, "", $regionId);
            if (!$model) {
                throw new \Exception("ecs不存在");
            }

            if ($name && $name != $model->name) {
                $result = $this->client->updateServer($instanceId, $name, $regionId);
                if (!$result) {
                    throw new \Exception('返回数据错误:' . $this->client->getError(false));
                }
            }

            if ($password) {
                $result = $this->client->resetServerPassword($instanceId, $password, $model->os_account, $regionId);
                if (!$result) {
                    throw new \Exception('返回数据错误:' . $this->client->getError(false));
                }
            }


            return true;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return false;
    }


    public function instanceVncPasswdModify(string $instanceId, string $vncPassword, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);

        return $this->instanceDescribe($instanceId, "", $regionId);
    }

    public function instanceVncUrlDescribe(string $instanceId, string $vncPassword = '', $regionId = ''): string
    {
        $regionId = $this->getRegionId($regionId);

        try {
            $instance = $this->instanceDescribe($instanceId);
            if (!$instance) {
                throw new \Exception('实例不存在');
            }

            $vncUrl = $this->client->showServerRemoteConsole($instanceId);

            if (!$vncUrl) {
                throw new \Exception('获取vnc地址失败');
            }

            return $vncUrl;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return '';
    }

    public function instanceChangeVpc(string $instanceId, string $vSwitchId, array $securityGroupId = [], $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        if (empty($instanceId)) {
            return true;
        }

        try {

            throw new \Exception('不支持通过接口切换vpc,请手动切换');
        } catch (\Exception $exception) {
            dump($exception);
            $this->setError($exception->getMessage());
        }
        return false;
    }

    public function systemDiskReplace(string $instanceId, string $imageId, string $password, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);

        try {

            $image = $this->imageDescribe($imageId);
            if (!$image) {
                throw new \Exception('镜像不存在');
            }

            $model = $this->instanceDescribe($instanceId);
            if (!$model) {
                throw new \Exception('实例不存在');
            }

            if ('Stopped' != $model->status) {
                throw new \Exception('请先停止实例');
            }

            if (!$password) {
                $password = $model->os_password;
            }

            $result = $this->client->reinstallServer($instanceId, $imageId, $password, $model->os_account, $regionId);


            if (!$result) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }
            $model->os_password = $password;

            $model->os_type = $image->os_type;
            $model->os_image = $image->asset_id;
            $model->os = $image->name;
            $model->status = 'Pending';

            $model->os_account = UtilStr::contains($model->os_type, 'Windows', false) ? 'administrator' : 'root';
            return $model;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }

    public function systemDiskSnapshotCreate(string $instanceId, string $name = '', $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $instanceId = trim($instanceId);
        if (!$instanceId) {
            return false;
        }

        try {
            $model = $this->instanceDescribe($instanceId);
            if (!$model) {
                throw new \Exception('实例不存在');
            }
            if (!$name) {
                $name = "s-" . date("Ymd-His");
            }
            if (!UtilStr::startsWith($name, $model->name)) {
                $name = $model->name . "-" . $name;
            }
            $result = $this->client->createServerSnapshot($instanceId, $name, $regionId);
            if (!$result) {
                throw new \Exception("接口返回错误:" . $this->client->getError(false));
            }
            return (bool)$result;

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }

        return false;
    }


    public function networkInterfaceCreate(string $vSwitchId, string $networkInterfaceName = null, array $securityGroupIds = [], $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);

        try {
            $client = $this->clientVpc();
            $datum = $client->createPort($vSwitchId, (string)$networkInterfaceName, $securityGroupIds, $regionId);
            if (!$datum) {
                throw new \Exception('接口返回错误:' . $client->getError(false));
            }
            $model = $this->formatEniToModel($datum);
            if (!$model) {
                throw new \Exception('返回数据错误');
            }

            return $model;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }


    public function networkInterfacesDescribe(array $networkInterfaceId = [], $instanceId = null, $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);

        $models = new AssetModels();

        try {
            if (!empty($networkInterfaceId)) {
                foreach ($networkInterfaceId as $id) {
                    if ($model = $this->networkInterfaceDescribe($id)) {
                        $models->push($model);
                    }

                }
                //　todo no api
                return $models;
            }

            $client = $this->clientVpc();
            $data = $client->showPorts("", (string)$instanceId, $regionId);
            if (is_null($data)) {
                throw new \Exception('接口返回错误:' . $client->getError(false));
            }


            foreach ($data as $datum) {
                if ($model = $this->formatEniToModel($datum)) {
                    $models->push($model);
                }
            }

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;
    }

    public function networkInterfaceDescribe(string $networkInterfaceId, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);
        try {
            $client = $this->clientVpc();
            $datum = $client->showPort($networkInterfaceId, $regionId);
            if (!$datum) {
                throw new \Exception('接口返回错误:' . $client->getError(false));
            }
            $model = $this->formatEniToModel($datum);
            if (!$model) {
                throw new \Exception('返回数据错误');
            }

            return $model;

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }

    public function networkInterfaceDelete(string $networkInterfaceId, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $networkInterfaceId = trim($networkInterfaceId);
        if (!$networkInterfaceId) {
            return false;
        }
        if (!$this->networkInterfaceDescribe($networkInterfaceId)) {
            return true;
        }
        try {
            $client = $this->clientVpc();
            $result = $client->deletePort($networkInterfaceId, $regionId);
            if (!$result) {
                throw new \Exception('接口返回错误:' . $client->getError(false));
            }
            return (bool)$result;
        } catch (ServiceResponseException $exception) {
            $this->setError($exception->getErrorMsg());
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return false;
    }

    public function networkInterfaceAttach(string $networkInterfaceId, string $instanceId, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);

        try {
            $networkInterfaceModel = $this->networkInterfaceDescribe($networkInterfaceId, $regionId);
            if (!$networkInterfaceModel) {
                throw new \Exception('弹性网卡不存在');
            }

            $instanceModel = $this->instanceDescribe($instanceId, "", $regionId);
            if (!$instanceModel) {
                throw new \Exception('实例不存在');
            }

            $client = $this->clientVpc();
            $datum = $client->portAttachInstance((string)$networkInterfaceModel->asset_id, (string)$instanceModel->asset_id, (string)$instanceModel->zone_id, $regionId);
            if (!$datum) {
                throw new \Exception('接口返回错误:' . $client->getError(false));
            }

            $instanceModel->second_ip = $networkInterfaceModel->primary_ip;
            return $instanceModel;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }

    public function networkInterfaceDetach(string $networkInterfaceId, string $instanceId, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);
        try {
            $networkInterfaceModel = $this->networkInterfaceDescribe($networkInterfaceId, $regionId);
            if (!$networkInterfaceModel) {
                throw new \Exception('弹性网卡不存在');
            }

            $instanceModel = $this->instanceDescribe($instanceId, "", $regionId);
            if (!$instanceModel) {
                throw new \Exception('实例不存在');
            }

            $client = $this->clientVpc();
            $datum = $client->portDetachInstance((string)$networkInterfaceModel->asset_id, $regionId);
            if (!$datum) {
                throw new \Exception('接口返回错误:' . $client->getError(false));
            }

            $instanceModel->second_ip = '';
            return $instanceModel;
        }  catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }


    public function commandCreate(string $commandContent, string $name, string $type = 'RunShellScript', $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);
        //todo noapi
        try {
            $id = $this->client->cloudAssistantCreateCommand((string)$commandContent,(string)$name,$this->formatCommandType($type), $regionId);
            if (!$id) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }
            $model = new AssetModel();
            $model->type = 'cmd';
            $model->asset_id = $id;

            $model->name = (string)$name;
            $model->os_type = (string)$type;
            $model->cmd_content = (string)$commandContent;
            $model->region_id = (string)$regionId;


            $model->status = 'Available';
            return $model;
        }  catch (\Exception $exception) {

            $this->setError($exception->getMessage());
        }
        return null;


    }

    public function commandsDescribe(string $commandId = null, string $name = null, string $type = null, $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);

        $models = new AssetModels();

        try {

            $data = $this->client->cloudAssistantListCommands((string)$commandId, (string)$name,(string)$this->formatCommandType($type), $regionId);
            if (is_null($data)) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }


            foreach ($data as $datum) {
                $id = UtilArr::get($datum,"commandID");
                if(!$id){
                    continue;
                }
                $model = new AssetModel();
                $model->type = 'cmd';
                $model->asset_id = $id;

                $model->name = (string)UtilArr::get($datum,"commandName","");
                $model->os_type = (string)$this->formatCommandType(UtilArr::get($datum,"commandType",""),true);
                $model->cmd_content = (string)UtilArr::get($datum,"commandContent","");
                $model->region_id = (string)$regionId;


                $model->status = 'Available';
                $models->push($model);
            }

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return $models;

    }

    public function commandDescribe(string $commandId, $regionId = ''): ?AssetModel
    {
        $models = $this->commandsDescribe($commandId, null, null, $regionId);
        if (!$models) {
            return null;
        }

        return $models->first(function ($item) use ($commandId) {
            return $item->asset_id == $commandId;
        });
    }

    public function commandDelete(string $commandId, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        try {
            $datum = $this->client->cloudAssistantDeleteCommand($commandId, $regionId);
            if (!$datum) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }
            return (bool)$datum;

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return false;

    }

    public function commandInvoke(string $commandId, array $instanceId, string $frequency = null, $regionId = ''): ?string
    {
        $regionId = $this->getRegionId($regionId);
        try {
            $id = $this->client->cloudAssistantInvokeCommand($commandId,$instanceId,60, $regionId);
            if (!$id) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }
            return $id;

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return "";
    }

    public function commandRun(string $commandContent, array $instanceIds, string $type = 'RunShellScript', string $contentEncoding = 'PlainText', $regionId = ''): ?string
    {
        $regionId = $this->getRegionId($regionId);
        try {
            $id = $this->client->cloudAssistantRunCommand($commandContent,$instanceIds,$this->formatCommandType($type),60, $regionId);
            if (!$id) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }
            return $id;

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return "";

    }

    public function commandInvocationsDescribe(string $invokeId = '', string $commandId = '', string $instanceId = '', $regionId = ''): ?array
    {
        $regionId = $this->getRegionId($regionId);
        try {
            $data = $this->client->cloudAssistantCommandInvocationDescribe($invokeId,$commandId,$regionId);
            if (is_null($data)) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }
            $models=[];
            foreach ($data as $datum){
                $invocationId = UtilArr::get($datum,"invokedID");
                if(!$invocationId){
                    continue;
                }
                $models['Invocations'][$invocationId] = $datum;
            }
            return $models;

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return [];

    }

    public function diskCreate(int $size, string $diskCategory = null, string $diskName = null, string $instanceId = null, string $zoneId = null, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);
        //todo api未完善，返回ID为空
        $this->setError("华为云接口有问题，斩不支持创建硬盘");
        return null;


        return null;
    }


    public function disksDescribe(array $diskIds = [], $instanceId = null, $regionId = ''): AssetModels
    {
        $regionId = $this->getRegionId($regionId);

        $models = new AssetModels();
        if (!empty($diskIds)) {
            foreach ($diskIds as $diskId) {
                $model = $this->diskDescribe($diskId, $regionId);
                if ($model) {
                    $models->push($model);
                }
            }
        }
        return $models;
    }

    public function diskDescribe(string $diskId, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);

        try {

            $datum = $this->client->volumeShow($diskId, $regionId);

            if (is_null($datum)) {
                throw new \Exception("接口返回错误:" . $this->client->getError(false));
            }

            $id = UtilArr::get($datum, "diskID");
            if (!$id) {
                throw new \Exception("接口返回数据错误");
            }

            $model = new AssetModel();
            $model->type = 'disk';
            $model->asset_id = $id;

            $model->name = UtilArr::get($datum, "diskName");
            $model->region_id = (string)$regionId;
            $model->zone_id = UtilArr::get($datum, "azName");
            $model->memory = UtilArr::get($datum, "diskSize");

            $model->bind_asset_id = UtilArr::get($datum, "instanceID");


            $model->status = UtilArr::get($datum, "diskStatus");

            return $model;

        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }

    public function diskUpdate(string $diskId, $name = '', $regionId = ''): ?AssetModel
    {
        $model = $this->diskDescribe($diskId, $regionId);
        if (!$model) {
            throw new \Exception('云盘不存在');
            return null;
        }
        $name = trim($name);
        if (!$name) {
            return $model;
        }

        try {

            $result = $this->client->volumeUpdate($model->asset_id, $name, $regionId);


            if (!(bool)$result) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }


            if ($name) {
                $model->name = $name;
            }
            return $model;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }


    public function diskAttach(string $diskId, string $instanceId, bool $bootable = false, bool $deleteWithInstance = false, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);

        try {
            $result = $this->client->volumeAttach($diskId, $instanceId, $regionId);
            if (!(bool)$result) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }

            return $this->diskDescribe($diskId);
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }

    public function diskDetach(string $diskId, string $instanceId, $regionId = ''): ?AssetModel
    {
        $regionId = $this->getRegionId($regionId);

        try {

            $result = $this->client->volumeDetach($diskId, $instanceId, $regionId);
            if (!(bool)$result) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }

            return $this->diskDescribe($diskId);
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return null;
    }


    public function diskDelete(string $diskId, $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $diskId = trim($diskId);
        if (!$diskId) {
            return false;
        }
        if (!$this->diskDescribe($diskId)) {
            return true;
        }
        try {
            $result = $this->client->volumeDelete($diskId, $regionId);
            if (!(bool)$result) {
                throw new \Exception('接口返回错误:' . $this->client->getError(false));
            }
            return (bool)$result;
        } catch (\Exception $exception) {
            $this->setError($exception->getMessage());
        }
        return false;
    }

    public function diskSnapshotCreate(string $diskId, string $name = '', $regionId = ''): bool
    {
        $regionId = $this->getRegionId($regionId);
        $this->setError("天翼云不支持按硬盘创建快照");
        return false;
    }


    protected function formatSecurityGroupRulePolicy($policy, $flip = false)
    {
        $arr = [
            'accept' => 'allow',
            'drop' => 'deny',
        ];
        if ($flip) {
            $arr = array_flip($arr);
        }

        return UtilArr::get($arr, $policy, '');
    }

    protected function formatArchitecture($architecture, $flip = false)
    {
        $arr = [
            'i386' => '32',
            'x86_64' => '64',
        ];
        if ($flip) {
            $arr = array_flip($arr);
        }

        return UtilArr::get($arr, $architecture, '');
    }

    protected function formatSecurityGroupRulePortRange($portRange)
    {
        $ports = explode('/', $portRange);
        if (count($ports) >= 2 && $ports[0] == $ports[1]) {
            $portRange = $ports[0];
        }
        if ('-1' == $portRange) {
            return null;
        }
        $portRange = UtilStr::replace($portRange, ['\/' => '-']);


        return $portRange;
    }


    /**
     * @param $datum ServerDetail
     * @return AssetModel|null
     */
    protected function formatServerDetailToModel($datum)
    {

        $id = UtilArr::get($datum, "instanceID");
        if (!$id) {
            //throw new \Exception("返回ID为空");
            return null;
        }


        $ipAddresses = UtilArr::get($datum, "networkCardList");

        $primaryAddress = UtilArr::get(UtilArr::get($ipAddresses, 0, null), "IPv4Address", "");
        $secondAddress = UtilArr::get(UtilArr::get($ipAddresses, 1, null), "IPv4Address", "");


        $model = new AssetModel();
        $model->type = 'ecs';
        $model->asset_id = $id;
        $model->name = UtilArr::get($datum, "instanceName");

        $model->os_type = 2 == UtilArr::get($datum, 'osType') ? "windows" : "linux";
        $model->instance_type = UtilArr::get($datum, 'flavor.flavorID');
        $model->region_id = "";
        $model->zone_id = UtilArr::get($datum, "azName");
        $model->cpu = UtilArr::get($datum, 'flavor.flavorCPU');
        $model->memory = UtilArr::get($datum, 'flavor.flavorRAM');
        $model->bandwidth = 0;
        $model->primary_ip = $primaryAddress;
        $model->second_ip = $secondAddress;

        $model->bind_asset_id = '';
        $model->public_ip = UtilArr::get($datum, 'floatingIP');
        if($model->public_ip){
            $vpcClient = $this->clientVpc();
            $eip = $vpcClient->showPublicip("",$model->public_ip);
            $eipId = UtilArr::get($eip,"ID");
            if($eipId){
                $model->bind_asset_id = $eipId;
            }
        }


        $model->os = UtilArr::get($datum, 'image.imageName');
        $model->os_image = UtilArr::get($datum, 'image.imageID');
        $model->os_account = UtilStr::contains($model->os_type, 'Windows', false) ? 'administrator' : 'root';
        $model->status = UtilArr::get($datum, "instanceStatus");
        $model->status = $this->formatEcsStatus($model->status);
        $model->pay_change_type = UtilArr::get($datum, 'onDemand') ? "PostPaid" : "PrePaid";
        return $model;
    }

    protected function formatEcsStatus($state)
    {
        //https://www.ctyun.cn/document/10026730/10741614
        $arr = [
            'error' => 'Pending',

            'running' => 'Running',

            'shelve' => 'Stopped',
            'stopped' => 'Stopped',


            'unsubscribed' => 'Deleted',
            'unsubscribing' => 'Deleted',
            'freezing' => 'Deleted',

        ];
        return UtilArr::get($arr, $state, 'Pending');
    }


    protected function formatInstanceTypeToModel($datum, $zoneId = "", $regionId = '')
    {
        $id = UtilArr::get($datum, "flavorID");
        if (!$id) {
            //throw new \Exception("返回数据ID为空");
            return null;
        }
        if (!$zoneId) {
            $zoneId = UtilArr::first(UtilArr::get($datum, "azList"));
        }
        $model = new AssetModel();
        $model->type = 'ecs_type';
        $model->asset_id = $id;
        $model->region_id = $regionId;
        $model->zone_id = $zoneId;
        $model->cpu = UtilArr::get($datum, "flavorCPU");
        $model->memory = 1024 * UtilArr::get($datum, "flavorRAM");
        $model->name = UtilArr::get($datum, "flavorName") . '-' . $model->cpu . '核' . ($model->memory / 1024) . 'G';
        return $model;
    }

    protected function formatEniToModel($datum)
    {
        //dump($datum);
        $id = UtilArr::get($datum, "networkInterfaceID", "");
        if (!$id) {
            return null;
        }

        $model = new AssetModel();
        $model->type = 'eni';
        $model->asset_id = $id;

        $model->name = UtilArr::get($datum, "networkInterfaceName", "");
        //$model->region_id = $this->getRegionId();
        $model->primary_ip = UtilArr::get($datum, "privateIpAddress", UtilArr::get($datum, "primaryPrivateIp", ""));
        $model->second_ip = '';

        $model->bind_asset_id = UtilArr::get($datum, "instanceID", "");

        $model->status = "active";
        return $model;
    }

    protected function formatDiskCategory($diskCategory, $flip = false)
    {
        $arr = [
            'cloud' => 'SAS',
            'cloud_efficiency' => 'SAS',
            'cloud_ssd' => 'GPSSD',
            'cloud_essd' => 'SSD',
        ];
        if ($flip) {
            $arr = array_flip($arr);
        }

        return UtilArr::get($arr, $diskCategory, '');
    }

    protected function formatPeriodUnit($diskCategory, $flip = false)
    {
        $arr = [
            'year' => 'month',
            'Week' => 'month',
            'Month' => 'month',
        ];
        if ($flip) {
            $arr = array_flip($arr);
        }

        return UtilArr::get($arr, $diskCategory, '');
    }

    protected function formatImageVisibilityToCode($visibility)
    {
        $arr = [
            'private' => 0,//'私有镜像',
            'public' => 1,//'公共镜像',
            'shared' => 2,//'共享镜像',
            'safe' => 3,//'安全产品镜像',
            'community' => 4,//'甄选镜像',
            'app' => 5,//'应用镜像',
        ];
        return UtilArr::get($arr, $visibility, 1);
    }

    protected function formatCommandType($t, $flip = false)
    {
        if(!$t){
            return "";
        }
        $arr = [
            'RunShellScript' => "shell",
            'RunBatScript' => "bat",
            'RunPowerShellScript' => "powerShell",
            'Python' => "python",
        ];
        if ($flip) {
            $arr = array_flip($arr);
        }
        return UtilArr::get($arr, $t, "");
    }

}

